package org.tweego 
{
	import org.tweego.events.TweegoEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import org.goasap.PlayableBase;
	import org.goasap.events.GoEvent;
	import org.goasap.events.SequenceEvent;
	import org.goasap.utils.Sequence;
	import org.goasap.utils.SequenceStep;
	import org.tweego.items.TweegoItem;	

	[Event(name="START", type="org.tweego.TweegoEvent")]
	[Event(name="STOP", type="org.tweego.TweegoEvent")]
	[Event(name="PAUSE", type="org.tweego.TweegoEvent")]
	[Event(name="RESUME", type="org.tweego.TweegoEvent")]
	[Event(name="COMPLETE", type="org.tweego.TweegoEvent")]
	[Event(name="CYCLE", type="org.tweego.TweegoEvent")]
	[Event(name="ADVANCE", type="org.tweego.TweegoEvent")]

	/**
	 * Tweego is a Fuse-like parser for the Go ASAP.
	 * Full documentation is missing right now :)
	 * 
	 * More info on:
	 * http://code.google.com/p/tweego
	 * http://www.sebastian-weyrauch.de
	 * 
	 * @author Sebastian Weyrauch
	 */
	public class Tweego extends EventDispatcher
	{
		protected var seq:Sequence;
		
		protected var defaultTarget:*;

		public function Tweego(...actions)
		{
			seq = new Sequence;
			if(actions.length>0) add.apply(this, actions);
		}
		
		/**
		 * Not recommend usage.
		 */
		public static function tween(target:*, action:Object):Tweego
		{
			var t:Tweego = new Tweego;
			t.target = target;
			t.push(action);
			t.start();
			
			return t;
		}
		
		public function set target(target:*):void
		{
			defaultTarget = target;
		}
		
		public function get target():*
		{
			return defaultTarget;
		}
		
		public function get duration():Number
		{
			var d:Number = 0;
			
			var steps:Array = seq.steps;
			for(var i:int = 0; i<steps.length; i++)
			{
				var currentStep:SequenceStep = SequenceStep(steps[i]);
				var children:Array = currentStep.children;
				//
				var maxStepDuration:Number = 0;
				for(var k:int = 0; k<children.length; k++)
				{
					var child:TweegoItem = TweegoItem(children[k]);
					maxStepDuration = Math.max(child.duration, maxStepDuration);
				}
				d += maxStepDuration;
			}
			
			return d;
		}
		
		public function set id(id:String):void
		{
			seq.playableID = id;
		}
		
		public function get id():String
		{
			return seq.playableID;
		}
		
		public function get state():String
		{
			return seq.state;
		}
		
		public function get currentId():*
		{
			var children:Array = seq.currentStep.children;
			if(children.length==1)
			{
				return PlayableBase(children[0]).playableID;
			}
			//
			var idList:Array = [];
			for(var i:int = 0; i<children.length; i++)
			{
				idList.push(PlayableBase(children[i]).playableID);
			}			
			return idList;
		}

		public function add(...actions):int
		{
			for(var i:int = 0; i<actions.length; i++)
			{
				var action:* = actions[i];
				
				// Multidimensional array
				if(action is Array)
				{
					var arr:Array = action;
					for(var k:int = 0; k<arr.length; k++)
					{
						addStep(arr[k], k>0);
					}
					continue;
				}
				
				addStep(actions[i]);
			}
			return i;
		}
		
		/**
		 * @see #add
		 */
		public function push(...actions):int
		{
			return add.apply(this, actions);
		}
		
		public function addStep(action:Object, addToLastStep:Boolean = false):void
		{
			if(action is Array)
			{
				throw new Error("Only single actions are allowed here.");
				return;
			}
			
			var target:* = action[TweegoProperties.TARGET] || defaultTarget;
			action[TweegoProperties.TARGET] = target;
			
			if(target is Array)
			{
				var targetList:Array = target as Array;
				for(var i:int = 0; i<targetList.length; i++) 
				{
					var newAction:Object = action;
					newAction[TweegoProperties.TARGET] = targetList[i];
					addStep(newAction, addToLastStep || i>0);
				}
				return;
			}
			
			seq.addStep(getItem(action), addToLastStep);
		}
		
		public function start():Boolean
		{
			return seq.start();
		}
		
		public function stop():Boolean
		{
			return seq.stop();
		}
		
		public function pause():Boolean
		{
			return seq.pause();
		}
		
		public function resume():Boolean
		{
			return seq.resume();
		}
		
		public function destroy():void
		{
			stop();
			//
			seq.removeEventListener(GoEvent.START, onEvent);
			seq.removeEventListener(GoEvent.STOP, onEvent);
			seq.removeEventListener(GoEvent.PAUSE, onEvent);
			seq.removeEventListener(GoEvent.RESUME, onEvent);
			seq.removeEventListener(GoEvent.COMPLETE, onEvent);
			seq.removeEventListener(GoEvent.CYCLE, onEvent);
			seq.removeEventListener(SequenceEvent.ADVANCE, onEvent);
			//
			seq = null;
			delete this;
		}
		
		public function skipTo(id:*):Boolean
		{
			var steps:Array = seq.steps;
			for(var i:int = 0; i<steps.length; i++)
			{
				var currentStep:SequenceStep = SequenceStep(steps[i]);
				var children:Array = currentStep.children;
				//
				for(var k:int = 0; k<children.length; k++)
				{
					var child:PlayableBase = PlayableBase(children[k]);
					if(child.playableID==id)
					{
						seq.stop();
						currentStep.start();
						return true;
					}
				}
			}
			
			return false;
		}
		
		public function clone():Tweego
		{
			var t:Tweego = new Tweego();
			t.target = target;
			t.seq.steps = seq.steps.concat();
						
			return t;
		}

		override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
		{
			super.addEventListener(type, listener, useCapture, priority, useWeakReference);
			//
			seq.addEventListener(type, onEvent, useCapture, priority, useWeakReference);
		}

		override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
		{
			super.removeEventListener(type, listener, useCapture);
			//
			seq.removeEventListener(type, onEvent, useCapture);
		}
		
		override public function toString():String 
		{
			var s:String = super.toString();
			var addLast:Boolean = (s.charAt(s.length-1)=="]");
			if (addLast) s = s.slice(0,-1);
			if (id is String) s += ", id: \"" + id + "\"";
			else s += ", id: " + id;
			s += ", state: "+seq.state;
			if (addLast) s += "]";
			return s;
		}

		protected function getItem(action:Object):TweegoItem
		{
			var item:TweegoItem = new TweegoItem(action);			
			return item;
		}
		
		private function onEvent(e:Event):void
		{
			var tweegoEvent:TweegoEvent = new TweegoEvent(e.type, e.bubbles, e.cancelable);
			dispatchEvent(tweegoEvent);
		}
	}
}
